import os, sqlite3, logging, socket
#from avahi_service import AvahiService
from avahi_search import AvahiSearch
from simple_parser import SimpleParser
import download_thread, signal

import pygtk
pygtk.require('2.0')
import gtk
import gobject

class GView:
    def __init__(self,pid,env):
        self.pid = pid
        self.env = env
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.vbox = gtk.VBox()
        self.hbox = gtk.HBox()
        self.sidebar = gtk.VBox()
        self.toolbar = gtk.Toolbar()
        self.toolbar.set_style(gtk.TOOLBAR_BOTH)

        self.netviewport = gtk.ScrolledWindow()
        self.netviewport.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.localviewport = gtk.ScrolledWindow()
        self.localviewport.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)

        ##############
        self.nettreestore = gtk.TreeStore(str,str,str)
        self.nettreeview = gtk.TreeView(self.nettreestore)

        self.nettvcolumn = gtk.TreeViewColumn('Other Computers')
        self.nettreeview.append_column(self.nettvcolumn)
        self.nettvcell = gtk.CellRendererText()

        self.nettvcolumn.pack_start(self.nettvcell, True)
        self.nettvcolumn.add_attribute(self.nettvcell, 'text', 0)
        self.nettvcolumn.set_sort_column_id(0)

        self.nettreeview.set_search_column(0)
        self.nettreeview.set_reorderable(True)
        ##############
        self.localtreestore = gtk.TreeStore(str)
        self.localtreeview = gtk.TreeView(self.localtreestore)

        self.localtvcolumn = gtk.TreeViewColumn('Shared')
        self.localtreeview.append_column(self.localtvcolumn)
        self.localtvcell = gtk.CellRendererText()

        self.localtvcolumn.pack_start(self.localtvcell, True)
        self.localtvcolumn.add_attribute( self.localtvcell, 'text', 0 )
        self.localtvcolumn.set_sort_column_id(0)

        self.localtreeview.set_search_column(0)
        self.localtreeview.set_reorderable(True)
        ##############

        self.progressStore = gtk.ListStore(int, str)
        self.progressStore.map = {}
        self.progressTree = gtk.TreeView(self.progressStore)

        self.ptvcolumnName = gtk.TreeViewColumn('File', 
            gtk.CellRendererText(), text=1)
        self.ptvcolumnState = gtk.TreeViewColumn('Finished',
            gtk.CellRendererProgress(), text=1, value=0, pulse=0)
        #self.ptvcolumnState.add_attribute(self.ptvcellName, 'progress', 1)

        self.progressTree.append_column(self.ptvcolumnName)
        self.progressTree.append_column(self.ptvcolumnState)

        self.dbut = gtk.ToolButton('Download')
        self.dbut.set_stock_id(gtk.STOCK_GO_DOWN)
        self.addbut = gtk.ToolButton('Add')
        self.addbut.set_stock_id(gtk.STOCK_ADD)
        self.rembut = gtk.ToolButton('Remove')
        self.rembut.set_stock_id(gtk.STOCK_REMOVE)
        self.qbut = gtk.ToolButton('Quit')
        self.qbut.set_stock_id(gtk.STOCK_QUIT)

        self.avsearch = AvahiSearch('_fhttp._tcp') #FIXME: hardcoded == bad
        self.QM = download_thread.QueryManager(5) #FIXME: hardcoded == bad
        self.DM = download_thread.DownloadManager(5)

        # signals
        self.avsearch.register_service_handler(self._add_server)

        self.qbut.connect("clicked",  self.delete_event)
        self.addbut.connect("clicked",  self.add_path)
        self.rembut.connect("clicked", self.rem_path)
        self.dbut.connect("clicked", self.download_path)
        self.window.connect("destroy", self.delete_event)

        # Construct layout
        self.window.add(self.vbox)
        self.localviewport.add_with_viewport(self.localtreeview)
        self.netviewport.add_with_viewport(self.nettreeview)

        self.vbox.pack_start(self.toolbar, expand=False)
        self.vbox.pack_start(self.hbox, expand=True)
        self.vbox.pack_end(self.progressTree,expand=False)

        self.hbox.pack_start(self.netviewport, expand=True)
        self.hbox.pack_end(self.localviewport, expand=True)

        self.toolbar.add(self.dbut)
        self.toolbar.add(self.addbut)
        self.toolbar.add(self.rembut)
        self.toolbar.add(self.qbut)

        self.window.set_size_request(500,500)
        self.window.show_all()
        self.prepopulate()

    def _add_server(self, name, address, ip, port):
        piter = self.nettreestore.append(None,row=(name+'@'+ip,str(ip),str(port)))
        self.QM.add_server_query((address,ip,port,piter), self.__add_net_paths)

    def __add_net_paths(self, *args):
        for path in args[0].paths:
            self.nettreestore.append(args[0].piter, [path, args[0].ip,  str(args[0].port)])

    def _rem_path(self, treemodel, path, iter):
        conn = sqlite3.connect( os.path.join(self.env.get('CONFIGDIR'), self.env.get('CONFIGLOC'), self.env.get('DBNAME')) )
        cursor = conn.cursor()
        cursor.execute("DELETE FROM "+self.env.get('DBTABLE')+" WHERE path = ? ;" , (treemodel[0][0],))
        conn.commit()
        self.localtreestore.remove(iter)

    def _download_completed(self, dthread, path, *args):
        logging.debug("MAP->"+str(self.progressStore.map))
        logging.info('finished download: '+str(args))
        piter = self.progressStore.map.get(path,False)
        if piter:
            self.progressStore.remove(piter)
            del(self.progressStore.map[path])
        else:
            logging.warning("Bad download completed path?")
            logging.info("Path %s and dict %s" % (path, str(self.progressStore.map)))

    def _chunk_completed(self, thread, path, *args):
        piter = self.progressStore.map.get(path, False)
        if piter:
            old = self.progressStore.get_value(piter,0)
            self.progressStore.set_value(piter,0,old+1)
        else:
            logging.info("Bad chunk path?")

    def _download_path(self, treemodel, path, iter):
        dpath = treemodel.get(iter,0)[0]
        dip = treemodel.get(iter,1)[0]
        dport = treemodel.get(iter,2)[0]

        logging.info("Download started")
        self.DM.add_download((dip, dport, dpath), self.env['DOWNLOADTO'], self._download_completed, self._chunk_completed)
        piter = self.progressStore.append(row=(0,dpath))
        self.progressStore.map[dpath] = piter
        logging.debug("MAP->"+str(self.progressStore.map))

    def delete_event(self, widget, event=None, data=None):
        # On the whole, this may be a bad idea
        gtk.main_quit()
        os.kill(self.pid, signal.SIGTERM) # cleanup other process
        return False

    def rem_path(self, widget):
        selected = self.localtreeview.get_selection()
        selected.selected_foreach(self._rem_path)

    def download_path(self, widget):
        selected = self.nettreeview.get_selection()
        selected.selected_foreach(self._download_path)

    def add_path(self, widget):
        chooser = gtk.FileChooserDialog(title='Add file or folder', buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK))
        response = chooser.run()
        if response == gtk.RESPONSE_OK:
            if os.path.exists( chooser.get_filename() ):
                if os.path.isdir( chooser.get_filename()):
                    logging.error('ERROR: full paths not yet implemented, just files, sorry')
                else:
                    conn = sqlite3.connect( os.path.join(self.env.get('CONFIGDIR'), self.env.get('CONFIGLOC'), self.env.get('DBNAME')) )
                    cursor = conn.cursor()
                    # FIXME: Deal with multiple selected files?

                    # Add to DB
                    cursor.execute('INSERT INTO ' + self.env.get('DBTABLE') + ' values ( ?, ?, ? ) ', (chooser.get_filename(), False, False))
                    conn.commit()
                    # Add to GUI
                    self.localtreestore.append(None, row=(chooser.get_filename(),) )

        chooser.destroy()

    def prepopulate(self):
        conn = sqlite3.connect( os.path.join(self.env.get('CONFIGDIR'), self.env.get('CONFIGLOC'), self.env.get('DBNAME')) )
        cursor = conn.cursor()
        paths = [x[0] for x in cursor.execute(self.env.get('SELECT_ALL_PATHS')).fetchall()]
        for path in paths:
            self.localtreestore.append(None, row=(path,))

                    

def Run(pid,env):
    """
    Provides a gtk gui to edit files you serve and find other files on the network
    """
    gobject.threads_init() # So gtk doesn't clobber itself

    view = GView(pid,env)
    gtk.main()
